package com.wangnian.wangcai.util;

import com.wangnian.wangcai.dao.DayInfo;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author 你懂的工具类
 */
public class Indicators {

    /**
     * 计算KDJ指标（同花顺9,3,3参数）- 优化版本
     * @param dayInfos 日线数据
     * @return double数组，包含K,D,J三个值
     */
    public static double[] calculateKDJ_THS(List<DayInfo> dayInfos) {
        int n = 9; // RSV周期
        int m1 = 3; // K值平滑周期
        int m2 = 3; // D值平滑周期
        
        if (dayInfos == null || dayInfos.size() < n) {
            throw new IllegalArgumentException("数据不足，无法计算 KDJ 指标。");
        }
        
        double k = 50; // K值初始为50
        double d = 50; // D值初始为50
        double[] result = new double[3];
        
        for (int i = n - 1; i < dayInfos.size(); i++) {
            // 使用循环查找最高价和最低价，避免Collections.max和min创建比较器对象
            double highestHigh = Double.MIN_VALUE;
            double lowestLow = Double.MAX_VALUE;
            
            // 在窗口内循环查找最高价和最低价
            for (int j = i - n + 1; j <= i; j++) {
                DayInfo info = dayInfos.get(j);
                if (info.getHigh() > highestHigh) {
                    highestHigh = info.getHigh();
                }
                if (info.getLow() < lowestLow) {
                    lowestLow = info.getLow();
                }
            }
            
            double close = dayInfos.get(i).getClose();
            
            double rsv;
            if (highestHigh - lowestLow < 0.000001) { // 避免浮点数精度问题
                rsv = 50; // 避免除零错误，设为中性值
            } else {
                rsv = (close - lowestLow) / (highestHigh - lowestLow) * 100;
            }
            
            // 更新K值和D值
            k = (m1 - 1) * k / m1 + rsv / m1;
            d = (m2 - 1) * d / m2 + k / m2;
        }
        
        result[0] = k;
        result[1] = d;
        result[2] = 3 * k - 2 * d; // J值
        return result;
    }

    /**
     * 计算KDJ指标（原实现）
     * @param dayInfos 日线数据
     * @param n 计算周期
     * @return J值
     */
    @Deprecated
    public static double calculateKDJ(List<DayInfo> dayInfos, int n) {
        if (dayInfos == null || dayInfos.size() < n) {
            throw new IllegalArgumentException("数据不足，无法计算 KDJ 指标。");
        }
        double k = 50; // K值初始为50
        double d = 50; // D值初始为50
        for (int i = n - 1; i < dayInfos.size(); i++) {
            // 使用循环查找最高价和最低价，避免创建子列表
            double highestHigh = Double.MIN_VALUE;
            double lowestLow = Double.MAX_VALUE;
            
            for (int j = i - n + 1; j <= i; j++) {
                DayInfo info = dayInfos.get(j);
                if (info.getHigh() > highestHigh) {
                    highestHigh = info.getHigh();
                }
                if (info.getLow() < lowestLow) {
                    lowestLow = info.getLow();
                }
            }
            
            double close = dayInfos.get(i).getClose();
            double rsv;
            if (highestHigh - lowestLow < 0.000001) {
                rsv = 50; // 避免除零错误，设为中性值
            } else {
                rsv = (close - lowestLow) / (highestHigh - lowestLow) * 100;
            }
            // 更新K值和D值
            k = (2.0 / 3.0) * k + (1.0 / 3.0) * rsv;
            d = (2.0 / 3.0) * d + (1.0 / 3.0) * k;
        }
        // 计算J值
        return 3 * k - 2 * d;
    }

    /**
     * 计算各种股票指标 - 移除不必要的System.out.println
     */
    public static void initIndicators(List<DayInfo> dayInfos) {
        if (dayInfos.isEmpty()) {
            return;
        }
        
        try {
            // 计算KDJ指标
            double[] kdjValues = calculateKDJ_THS(dayInfos);
            DayInfo lastDayInfo = dayInfos.get(dayInfos.size() - 1);
            lastDayInfo.setK(kdjValues[0]);
            lastDayInfo.setD(kdjValues[1]);
            lastDayInfo.setJ(kdjValues[2]);
        } catch (Exception e) {
            // 异常处理，防止计算失败导致程序崩溃
            org.slf4j.LoggerFactory.getLogger(Indicators.class).error("计算指标失败", e);
        }
    }

    public void process(List<DayInfo> dayInfoList) {
        int day = 2;
        for (int i = day; i < dayInfoList.size(); i++) {
            DayInfo dayInfo = dayInfoList.get(i);
            Double sumClose = 0D;
            for (int x = day; x >= 0; x--) {
                sumClose += dayInfoList.get(i - x).getClose();
            }
            Double avg = sumClose / (day + 1);
            DayInfo dayInfo1 = dayInfoList.get(i - 1);
            dayInfo.setAvg3(avg);
            dayInfo.setAvg3Pre(dayInfo1.getAvg3());

            if (dayInfo.getAvg3Pre() != null) {
                dayInfo.setAvg3Differ(avg - dayInfo.getAvg3Pre());
            }
        }
    }

    /**
     * 涨幅
     *
     * @param a
     * @param b
     * @return
     */
    public static double zf(double a, double b) {
        return (a - b) / b * 100;
    }

    /**
     * 涨幅多少等于多少
     *
     * @param a
     * @param zf
     * @return
     */
    public static double plusZf(double a, double zf) {
        return zf / 100 * a + a;
    }

    /**
     * 减仓获取新的成本
     *
     * @param price
     * @param cost
     * @param oldCount
     * @param newCount
     * @return
     */
    public static double LessGetNewCost(double price, double cost, int oldCount, int newCount) {
        return (cost * oldCount - price * newCount) / newCount;
    }

    /**
     * 加仓获取新的成本
     *
     * @param price
     * @param cost
     * @param oldCount
     * @param newCount
     * @return
     */
    public static double plusGetNewCost(double price, double cost, int oldCount, int newCount) {
        return (cost * oldCount + price * newCount) / (newCount + oldCount);
    }
}
